home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / imap / ANSI / ipopd / ipop2d.c next >
C/C++ Source or Header  |  1997-02-25  |  14KB  |  544 lines

  1. /*
  2.  * Program:    IPOP2D - IMAP2 to POP2 conversion server
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    28 October 1990
  13.  * Last Edited:    25 February 1997
  14.  *
  15.  * Copyright 1997 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36.  
  37. /* Parameter files */
  38.  
  39. #include "mail.h"
  40. #include "osdep.h"
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include <netdb.h>
  44. #include <errno.h>
  45. extern int errno;        /* just in case */
  46. #include <signal.h>
  47. #include <pwd.h>
  48. #include "misc.h"
  49.  
  50.  
  51. /* Autologout timer */
  52. #define TIMEOUT 60*30
  53.  
  54.  
  55. /* Size of temporary buffers */
  56. #define TMPLEN 1024
  57.  
  58.  
  59. /* Server states */
  60.  
  61. #define LISN 0
  62. #define AUTH 1
  63. #define MBOX 2
  64. #define ITEM 3
  65. #define NEXT 4
  66. #define DONE 5
  67.  
  68. /* Global storage */
  69.  
  70. char *version = "2.3(17)";    /* server version */
  71. short state = LISN;        /* server state */
  72. MAILSTREAM *stream = NIL;    /* mailbox stream */
  73. long nmsgs = 0;            /* number of messages */
  74. long current = 1;        /* current message number */
  75. long size = 0;            /* size of current message */
  76. char status[MAILTMPLEN];    /* space for status string */
  77. char *user = "";        /* user name */
  78. char *pass = "";        /* password */
  79. short *msg = NIL;        /* message translation vector */
  80.  
  81.  
  82. /* Function prototypes */
  83.  
  84. void main (int argc,char *argv[]);
  85. void clkint ();
  86. void kodint ();
  87. short c_helo (char *t,int argc,char *argv[]);
  88. short c_fold (char *t);
  89. short c_read (char *t);
  90. short c_retr (char *t);
  91. short c_acks (char *t);
  92. short c_ackd (char *t);
  93. short c_nack (char *t);
  94.  
  95. /* Main program */
  96.  
  97. void main (int argc,char *argv[])
  98. {
  99.   char *s,*t;
  100.   struct hostent *hst;
  101.   char cmdbuf[TMPLEN];
  102. #include "linkage.c"
  103.   openlog ("ipop2d",LOG_PID,LOG_MAIL);
  104.   gethostname (status,TMPLEN-1);/* get local name */
  105.   s = cpystr ((hst = gethostbyname (status)) ? hst->h_name : status);
  106.   rfc822_date (cmdbuf);        /* get date/time now */
  107.   printf ("+ %s POP2 %s w/IMAP2 client %s at %s\015\012",s,version,
  108.       "(Comments to MRC@CAC.Washington.EDU)",cmdbuf);
  109.   fflush (stdout);        /* dump output buffer */
  110.   signal (SIGALRM,clkint);    /* prepare for clock interrupt */
  111.   signal (SIGUSR2,kodint);    /* prepare for Kiss Of Death */
  112.   state = AUTH;            /* initial server state */
  113.   while (state != DONE) {    /* command processing loop */
  114.     alarm (TIMEOUT);        /* get a command under timeout */
  115.     while (!fgets (cmdbuf,TMPLEN-1,stdin)) {
  116.       if (errno==EINTR) errno=0;/* ignore if some interrupt */
  117.       else {
  118.     syslog (LOG_INFO,"Connection broken while reading line from %.80s",
  119.         tcp_clienthost (cmdbuf));
  120.     _exit (1);
  121.       }
  122.     }
  123.     alarm (0);            /* make sure timeout disabled */
  124.                 /* find end of line */
  125.     if (!strchr (cmdbuf,'\012')) {
  126.       puts ("- Command line too long\015");
  127.       state = DONE;
  128.     }
  129.     else if (!(s = strtok (cmdbuf," \015\012"))) {
  130.       puts ("- Missing or null command\015");
  131.       state = DONE;
  132.     }
  133.     else {            /* dispatch based on command */
  134.       ucase (s);        /* canonicalize case */
  135.                 /* snarf argument */
  136.       t = strtok (NIL,"\015\012");
  137.       if ((state == AUTH) && !strcmp (s,"HELO")) state = c_helo (t,argc,argv);
  138.       else if ((state == MBOX || state == ITEM) && !strcmp (s,"FOLD"))
  139.     state = c_fold (t);
  140.       else if ((state == MBOX || state == ITEM) && !strcmp (s,"READ"))
  141.     state = c_read (t);
  142.       else if ((state == ITEM) && !strcmp (s,"RETR")) state = c_retr (t);
  143.       else if ((state == NEXT) && !strcmp (s,"ACKS")) state = c_acks (t);
  144.       else if ((state == NEXT) && !strcmp (s,"ACKD")) state = c_ackd (t);
  145.       else if ((state == NEXT) && !strcmp (s,"NACK")) state = c_nack (t);
  146.       else if ((state == AUTH || state == MBOX || state == ITEM) &&
  147.            !strcmp (s,"QUIT")) {
  148.     if (t) puts ("- Bogus argument given to QUIT\015");
  149.     else {            /* valid sayonara */
  150.                 /* expunge the stream */
  151.       if (stream && nmsgs) mail_expunge (stream);
  152.       puts ("+ Sayonara\015");/* acknowledge the command */
  153.     }
  154.     state = DONE;        /* done in either case */
  155.       }
  156.       else {            /* some other or inappropriate command */
  157.     printf ("- Bogus or out of sequence command - %s\015\012",s);
  158.     state = DONE;
  159.       }
  160.     }
  161.     fflush (stdout);        /* make sure output blatted */
  162.   }
  163.   mail_close (stream);        /* clean up the stream */
  164.   syslog (LOG_INFO,"Logout from %.80s",tcp_clienthost (cmdbuf));
  165.   exit (0);            /* all done */
  166. }
  167.  
  168. /* Clock interrupt
  169.  */
  170.  
  171. void clkint ()
  172. {
  173.   char tmp[MAILTMPLEN];
  174.   puts ("- Autologout; idle for too long\015");
  175.   syslog (LOG_INFO,"Autologout user=%.80s host=%.80s",user ? user : "???",
  176.       tcp_clienthost (tmp));
  177.   fflush (stdout);        /* make sure output blatted */
  178.   mail_close (stream);        /* try to gracefully close the stream */
  179.   stream = NIL;
  180.   exit (0);            /* die die die */
  181. }
  182.  
  183.  
  184. /* Kiss Of Death interrupt
  185.  */
  186.  
  187. void kodint ()
  188. {
  189.   char tmp[MAILTMPLEN];
  190.   puts ("- Received Kiss of Death\015");
  191.   syslog (LOG_INFO,"Kiss of death user=%.80s host=%.80s",user ? user : "???",
  192.       tcp_clienthost (tmp));
  193.   fflush (stdout);        /* make sure output blatted */
  194.   mail_close (stream);        /* try to gracefully close the stream */
  195.   stream = NIL;
  196.   exit (0);            /* die die die */
  197. }
  198.  
  199. /* Parse HELO command
  200.  * Accepts: pointer to command argument
  201.  * Returns: new state
  202.  */
  203.  
  204. short c_helo (char *t,int argc,char *argv[])
  205. {
  206.   unsigned long i;
  207.   char *s,*u,*p;
  208.   char tmp[TMPLEN];
  209.   struct passwd *pwd = getpwnam ("nobody");
  210.   if (!(t && *t && (u = strtok (t," ")) && (p = strtok (NIL,"\015\012")))) {
  211.     puts ("- Missing user or password\015");
  212.     return DONE;
  213.   }
  214.                 /* copy password, handle quoting */
  215.   for (s = tmp; *p; p++) *s++ = (*p == '\\') ? *++p : *p;
  216.   *s = '\0';            /* tie off string */
  217.   pass = cpystr (tmp);
  218.   if (s = strchr (u,':')) {    /* want remote mailbox? */
  219.     *s++ = '\0';        /* separate host name from user name */
  220.     user = cpystr (s);        /* note user name */
  221.     syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%s",u,user,
  222.         tcp_clienthost (tmp));
  223.     sprintf (tmp,"{%s}INBOX",u);/* initially remote INBOX */
  224.     if (pwd) {            /* try to become someone harmless */
  225.       setgid (pwd->pw_gid);    /* set group ID */
  226.       setuid (pwd->pw_uid);    /* and user ID */
  227.     }
  228.   }
  229.   else if (((i = strlen (u)) < 64) &&
  230.        server_login (user = cpystr (u),pass,NIL,argc,argv)) {
  231.     syslog (LOG_INFO,"Login user=%.80s host=%.80s",user,tcp_clienthost (tmp));
  232.     strcpy (tmp,"INBOX");    /* local; attempt login, select INBOX */
  233.   }
  234.   else {
  235.     if (i > 128) syslog (LOG_ALERT|LOG_AUTH,"Crack attempt, host=%.80s",
  236.              tcp_clienthost (tmp));
  237.     sleep (3);            /* slow the cracker down */
  238.     puts ("- Bad login\015");
  239.     syslog (LOG_INFO,"Login failure user=%.80s host=%.80s",user,
  240.         tcp_clienthost(tmp));
  241.     return DONE;
  242.   }
  243.   return c_fold (tmp);        /* open default mailbox */
  244. }
  245.  
  246. /* Parse FOLD command
  247.  * Accepts: pointer to command argument
  248.  * Returns: new state
  249.  */
  250.  
  251. short c_fold (char *t)
  252. {
  253.   long i,j;
  254.   char *s,tmp[TMPLEN];
  255.   if (!(t && *t)) {        /* make sure there's an argument */
  256.     puts ("- Missing mailbox name\015");
  257.     return DONE;
  258.   }
  259.                 /* expunge old stream */
  260.   if (stream && nmsgs) mail_expunge (stream);
  261.   nmsgs = 0;            /* no more messages */
  262.   if (msg) fs_give ((void **) &msg);
  263.                 /* don't permit proxy to leave IMAP */
  264.   if (stream && stream->mailbox && (s = strchr (stream->mailbox,'}'))) {
  265.     strncpy (tmp,stream->mailbox,i = (++s - stream->mailbox));
  266.     strcpy (tmp+i,t);        /* append mailbox to initial spec */
  267.     t = tmp;
  268.   }
  269.                 /* open mailbox, note # of messages */
  270.   if (j = (stream = mail_open (stream,t,NIL)) ? stream->nmsgs : 0) {
  271.     sprintf (tmp,"1:%d",j);    /* fetch fast information for all messages */
  272.     mail_fetchfast (stream,tmp);
  273.     msg = (short *) fs_get ((stream->nmsgs + 1) * sizeof (short));
  274.     for (i = 1; i <= j; i++)    /* find undeleted messages, add to vector */
  275.       if (!mail_elt (stream,i)->deleted) msg[++nmsgs] = i;
  276.   }
  277.   printf ("#%d messages in %s\015\012",nmsgs,stream ? stream->mailbox :
  278.       "<none>");
  279.   return MBOX;
  280. }
  281.  
  282. /* Parse READ command
  283.  * Accepts: pointer to command argument
  284.  * Returns: new state
  285.  */
  286.  
  287. short c_read (char *t)
  288. {
  289.   MESSAGECACHE *elt = NIL;
  290.   if (t && *t) {        /* have a message number argument? */
  291.     current = atoi (t);        /* set message number if possible */
  292.                 /* validity check message number */
  293.     if (current < 1 || current > nmsgs) {
  294.       puts ("- Invalid message number given to READ\015");
  295.       return DONE;
  296.     }
  297.   }
  298.   else if (current > nmsgs) {    /* at end of mailbox? */
  299.     puts ("=0 No more messages\015");
  300.     return MBOX;
  301.   }
  302.                 /* set size if message valid and exists */
  303.   size = msg[current] ? (elt = mail_elt(stream,msg[current]))->rfc822_size : 0;
  304.   if (elt) sprintf (status,"Status: %s%s\015\012",
  305.             elt->seen ? "R" : " ",elt->recent ? " " : "O");
  306.   else status[0] = '\0';    /* no status */
  307.   size += strlen (status);    /* update size to reflect status */
  308.                 /* display results */
  309.   printf ("=%d characters in message %d\015\012",size,current);
  310.   return ITEM;
  311. }
  312.  
  313.  
  314. /* Parse RETR command
  315.  * Accepts: pointer to command argument
  316.  * Returns: new state
  317.  */
  318.  
  319. short c_retr (char *t)
  320. {
  321.   char c,*s;
  322.   if (t) {            /* disallow argument */
  323.     puts ("- Bogus argument given to RETR\015");
  324.     return DONE;
  325.   }
  326.   if (size) {            /* message size valid? */
  327.     fputs (status,stdout);    /* yes, output message */
  328.     fputs (mail_fetchheader (stream,msg[current]),stdout);
  329.     fputs (mail_fetchtext (stream,msg[current]),stdout);
  330.   }
  331.   else return DONE;        /* otherwise go away */
  332.   return NEXT;
  333. }
  334.  
  335. /* Parse ACKS command
  336.  * Accepts: pointer to command argument
  337.  * Returns: new state
  338.  */
  339.  
  340. short c_acks (char *t)
  341. {
  342.   char tmp[TMPLEN];
  343.   if (t) {            /* disallow argument */
  344.     puts ("- Bogus argument given to ACKS\015");
  345.     return DONE;
  346.   }
  347.                 /* mark message as seen */
  348.   sprintf (tmp,"%d",msg[current++]);
  349.   mail_setflag (stream,tmp,"\\Seen");
  350.   return c_read (NIL);        /* end message reading transaction */
  351. }
  352.  
  353.  
  354. /* Parse ACKD command
  355.  * Accepts: pointer to command argument
  356.  * Returns: new state
  357.  */
  358.  
  359. short c_ackd (char *t)
  360. {
  361.   char tmp[TMPLEN];
  362.   if (t) {            /* disallow argument */
  363.     puts ("- Bogus argument given to ACKD\015");
  364.     return DONE;
  365.   }
  366.                 /* mark message as seen and deleted */
  367.   sprintf (tmp,"%d",msg[current]);
  368.   mail_setflag (stream,tmp,"\\Seen \\Deleted");
  369.   msg[current++] = 0;        /* mark message as deleted */
  370.   return c_read (NIL);        /* end message reading transaction */
  371. }
  372.  
  373.  
  374. /* Parse NACK command
  375.  * Accepts: pointer to command argument
  376.  * Returns: new state
  377.  */
  378.  
  379. short c_nack (char *t)
  380. {
  381.   if (t) {            /* disallow argument */
  382.     puts ("- Bogus argument given to NACK\015");
  383.     return DONE;
  384.   }
  385.   return c_read (NIL);        /* end message reading transaction */
  386. }
  387.  
  388. /* Co-routines from MAIL library */
  389.  
  390.  
  391. /* Message matches a search
  392.  * Accepts: MAIL stream
  393.  *        message number
  394.  */
  395.  
  396. void mm_searched (MAILSTREAM *stream,long msgno)
  397. {
  398.   /* Never called */
  399. }
  400.  
  401.  
  402. /* Message exists (i.e. there are that many messages in the mailbox)
  403.  * Accepts: MAIL stream
  404.  *        message number
  405.  */
  406.  
  407. void mm_exists (MAILSTREAM *stream,long number)
  408. {
  409.   /* Can't use this mechanism.  POP has no means of notifying the client of
  410.      new mail during the session. */
  411. }
  412.  
  413.  
  414. /* Message expunged
  415.  * Accepts: MAIL stream
  416.  *        message number
  417.  */
  418.  
  419. void mm_expunged (MAILSTREAM *stream,long number)
  420. {
  421.   /* This isn't used */
  422. }
  423.  
  424.  
  425. /* Message status changed
  426.  * Accepts: MAIL stream
  427.  *        message number
  428.  */
  429.  
  430. void mm_flags (MAILSTREAM *stream,long number)
  431. {
  432.   /* This isn't used */
  433. }
  434.  
  435.  
  436. /* Mailbox found
  437.  * Accepts: Mailbox name
  438.  */
  439.  
  440. void mm_mailbox (char *string)
  441. {
  442.   /* This isn't used */
  443. }
  444.  
  445.  
  446. /* BBoard found
  447.  * Accepts: BBoard name
  448.  */
  449.  
  450. void mm_bboard (char *string)
  451. {
  452.   /* This isn't used */
  453. }
  454.  
  455. /* Notification event
  456.  * Accepts: MAIL stream
  457.  *        string to log
  458.  *        error flag
  459.  */
  460.  
  461. void mm_notify (MAILSTREAM *stream,char *string,long errflg)
  462. {
  463.   mm_log (string,errflg);    /* just do mm_log action */
  464. }
  465.  
  466.  
  467. /* Log an event for the user to see
  468.  * Accepts: string to log
  469.  *        error flag
  470.  */
  471.  
  472. void mm_log (char *string,long errflg)
  473. {
  474.   /* Not doing anything here for now */
  475. }
  476.  
  477.  
  478. /* Log an event to debugging telemetry
  479.  * Accepts: string to log
  480.  */
  481.  
  482. void mm_dlog (char *string)
  483. {
  484.   /* Not doing anything here for now */
  485. }
  486.  
  487.  
  488. /* Get user name and password for this host
  489.  * Accepts: host name
  490.  *        where to return user name
  491.  *        where to return password
  492.  *        trial count
  493.  */
  494.  
  495. void mm_login (char *host,char *username,char *password,long trial)
  496. {
  497.   strcpy (username,user);    /* set user name */
  498.   strcpy (password,pass);    /* and password */
  499. }
  500.  
  501. /* About to enter critical code
  502.  * Accepts: stream
  503.  */
  504.  
  505. void mm_critical (MAILSTREAM *stream)
  506. {
  507.   /* Not doing anything here for now */
  508. }
  509.  
  510.  
  511. /* About to exit critical code
  512.  * Accepts: stream
  513.  */
  514.  
  515. void mm_nocritical (MAILSTREAM *stream)
  516. {
  517.   /* Not doing anything here for now */
  518. }
  519.  
  520.  
  521. /* Disk error found
  522.  * Accepts: stream
  523.  *        system error code
  524.  *        flag indicating that mailbox may be clobbered
  525.  * Returns: abort flag
  526.  */
  527.  
  528. long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
  529. {
  530.   syslog (LOG_ALERT,"Retrying after disk error %.80s",strerror (errcode));
  531.   sleep (5);            /* can't do much better than this! */
  532.   return NIL;
  533. }
  534.  
  535.  
  536. /* Log a fatal error event
  537.  * Accepts: string to log
  538.  */
  539.  
  540. void mm_fatal (char *string)
  541. {
  542.   mm_log (string,ERROR);    /* shouldn't happen normally */
  543. }
  544.